home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 23 / AACD 23.iso / AACD / Online / opennap / init.c < prev    next >
C/C++ Source or Header  |  2001-06-08  |  10KB  |  382 lines

  1. /* Copyright (C) 2000-1 drscholl@users.sourceforge.net
  2.    This is free software distributed under the terms of the
  3.    GNU Public License.  See the file COPYING for details.
  4.  
  5.    $Id: init.c,v 1.62 2001/03/03 01:00:05 drscholl Exp $ */
  6.  
  7. /* Modified 30/05/01 : Added defines for USE_GID and USE_UID, since we are not
  8.       for Amiga port : using the CONFIGURE script
  9.  
  10.                        Added include "confdefs.h" since we are not using the
  11.                        CONFIGURE script
  12.  
  13.                        Added include "extrasocket.h" with inlines for a few
  14.                        bsdsocket.library functions not emulated by ixemul
  15. */
  16.  
  17. #define USE_GID "nobody"
  18. #define USE_UID "nobody"
  19.  
  20. #include "confdefs.h"
  21.  
  22. #ifndef WIN32
  23. #include <grp.h>
  24. #include <pwd.h>
  25. #include <unistd.h>
  26. #include <sys/types.h>
  27. #include <netdb.h>
  28. #include <limits.h>
  29. #if HAVE_MLOCKALL
  30. #include <sys/mman.h>
  31. #endif /* HAVE_MLOCKALL */
  32. #endif /* !WIN32 */
  33. #include <signal.h>
  34. #include <time.h>
  35. #include <stdio.h>
  36. #include <string.h>
  37. #include <errno.h>
  38. #include <sys/stat.h>
  39. #include <fcntl.h>
  40. #include <stdlib.h>
  41. #ifndef WIN32
  42. #include <netinet/in.h>
  43. #include <arpa/inet.h>
  44. #endif
  45. #ifdef __EMX__
  46. #include <stdlib.h>
  47. #define _POSIX_PATH_MAX _MAX_PATH
  48. #endif /* __EMX__ */
  49. #include "opennap.h"
  50. #include "hashlist.h"
  51. #include "debug.h"
  52.  
  53. #include "extrasocket.h"
  54.  
  55. static void
  56. lookup_hostname (void)
  57. {
  58.     struct hostent *he;
  59.  
  60.     /* get our canonical host name */
  61.     gethostname (Buf, sizeof (Buf));
  62.     he = gethostbyname (Buf);
  63.     if (he)
  64.         Server_Name = STRDUP (he->h_name);
  65.     else
  66.     {
  67.         log ("lookup_hostname: unable to find fqdn for %s", Buf);
  68.         Server_Name = STRDUP (Buf);
  69.     }
  70. }
  71.  
  72. #if !defined( WIN32) || defined(__CYGWIN__)
  73. static void
  74. sighandler (int sig)
  75. {
  76.     log ("sighandler: caught signal %d", sig);
  77.     switch (sig)
  78.     {
  79.     case SIGINT:
  80.     case SIGHUP:
  81.     case SIGTERM:
  82.         SigCaught = 1;
  83.         break;
  84.     case SIGUSR1:
  85.         CLEANUP ();
  86.         break;
  87.     }
  88. }
  89.  
  90. #if defined(PARANOID) && defined(DEBUG)
  91. static void
  92. wipe_user_pass (USER * user, void *unused)
  93. {
  94.     (void) unused;
  95.     memset (user->pass, 0, strlen (user->pass));
  96. }
  97.  
  98. static void
  99. wipe_server_pass (server_auth_t * auth)
  100. {
  101.     memset (auth->their_pass, 0, strlen (auth->their_pass));
  102.     memset (auth->my_pass, 0, strlen (auth->my_pass));
  103. }
  104.  
  105. static void
  106. handle_sigsegv (int sig)
  107. {
  108.     struct sigaction sa;
  109.  
  110.     memset (&sa, 0, sizeof (sa));
  111.     sa.sa_handler = SIG_DFL;
  112.     sigaction (SIGSEGV, &sa, 0);        /* set back to default */
  113.  
  114.     /* every C primer says not to do this, but it seems to work... =) */
  115.     fprintf (stderr, "handle_sigsegv: caught sigsegv, wiping passwords\n");
  116.     fflush (stderr);
  117.  
  118.     (void) sig;
  119.     /* wipe the user/server passwords before dumping core */
  120.     hash_foreach (User_Db, (hash_callback_t) wipe_user_pass, 0);
  121.     list_foreach (Server_Auth, (list_callback_t) wipe_server_pass, 0);
  122.  
  123.     kill (getpid (), SIGSEGV);  /* raise the signal again so we get a core */
  124. }
  125. #endif /* PARANOID */
  126.  
  127. static int
  128. drop_privs (void)
  129. {
  130.     int     n;
  131.     char   *p;
  132.     struct passwd *pw;
  133.     struct group *gr;
  134.  
  135.     n = strtol (USE_GID, &p, 10);
  136.     if (p)
  137.     {
  138.         /* probably a string */
  139.         gr = getgrnam (USE_GID);
  140.         if (!gr)
  141.         {
  142.             log ("drop_privs: unable to find gid for group %s", USE_GID);
  143.             return -1;
  144.         }
  145.         n = gr->gr_gid;
  146.     }
  147.     if (setgid (n))
  148.     {
  149.         logerr ("drop_privs", "setgid");
  150.         return -1;
  151.     }
  152.  
  153.     n = strtol (USE_UID, &p, 10);
  154.     if (p)
  155.     {
  156.         /* probably a string */
  157.         pw = getpwnam (USE_UID);
  158.         if (!pw)
  159.         {
  160.             log ("drop_privs: unable to find uid for user %s", USE_UID);
  161.             return -1;
  162.         }
  163.         n = pw->pw_uid;
  164.     }
  165.     if (setuid (n))
  166.     {
  167.         logerr ("drop_privs", "setuid");
  168.         return -1;
  169.     }
  170.  
  171.     return 0;
  172. }
  173. #endif
  174.  
  175. /* write the pid to a file so an external program can check to see if the
  176.    process is still running. */
  177. static void
  178. dump_pid (void)
  179. {
  180.     FILE   *f;
  181.     char    path[_POSIX_PATH_MAX];
  182.  
  183.     log ("dump_pid: pid is %d", getpid ());
  184.     snprintf (path, sizeof (path), "%s/pid", Config_Dir);
  185.     f = fopen (path, "w");
  186.     if (!f)
  187.     {
  188.         logerr ("dump_pid", path);
  189.         return;
  190.     }
  191.     fprintf (f, "%d\n", (int) getpid ());
  192.     fclose (f);
  193. }
  194.  
  195. int
  196. init_server (void)
  197. {
  198. #if !defined( WIN32) || defined(__CYGWIN__)
  199.     struct sigaction sa;
  200.  
  201.     memset (&sa, 0, sizeof (sa));
  202.     sa.sa_handler = sighandler;
  203.     sigaction (SIGHUP, &sa, NULL);
  204.     sigaction (SIGTERM, &sa, NULL);
  205.     sigaction (SIGINT, &sa, NULL);
  206.     sigaction (SIGPIPE, &sa, NULL);
  207. #if !defined( __EMX__) && !defined(__CYGWIN__)
  208.     sa.sa_flags = SA_RESTART;
  209. #endif /* ! __EMX__ */
  210.     sigaction (SIGUSR1, &sa, NULL);
  211.     sigaction (SIGALRM, &sa, NULL);
  212. #ifdef PARANOID
  213. #ifndef DEBUG
  214.     sa.sa_handler = handle_sigsegv;
  215.     sigaction (SIGSEGV, &sa, NULL);
  216. #endif /* DEBUG */
  217. #endif /* PARANOID */
  218. #endif /* !WIN32 */
  219.  
  220.     global.stat_server_fd = -1;
  221.  
  222.     log ("init_server: version %s starting", VERSION);
  223.  
  224.     Server_Start = time (&global.current_time);
  225.  
  226.     /* load default configuration values */
  227.     config_defaults ();
  228.  
  229.     /* load the config file - note that if CHROOT is defined we are already
  230.      * chrooted when we get here.  we are also running as uid 0 because
  231.      * some of the ulimit's might need to be altered before starting up.
  232.      * so read the config file now, set limits and then drop privs before
  233.      * loading any other files.
  234.      */
  235.     if (config (1))
  236.         return -1;
  237.  
  238. #if !defined(WIN32) && !defined(__EMX__)
  239.     /* change umask to something more secure */
  240.     umask (077);
  241.  
  242.     if (set_max_connections (Connection_Hard_Limit))
  243.         return -1;
  244.     if (Max_Data_Size != -1 && set_data_size (Max_Data_Size))
  245.         return -1;
  246.     if (Max_Rss_Size != -1 && set_rss_size (Max_Rss_Size))
  247.         return -1;
  248. #if HAVE_MLOCKALL
  249.     /* prevent swapping by locking all memory into real memory */
  250.     if (option (ON_LOCK_MEMORY) && mlockall (MCL_CURRENT | MCL_FUTURE))
  251.         logerr ("init_server", "mlockall");
  252. #endif /* HAVE_MLOCKALL */
  253.  
  254.     if (getuid () == 0)
  255.         drop_privs ();
  256.     ASSERT (getuid () != 0);
  257.     ASSERT (getgid () != 0);
  258.  
  259.     /* log message to show that we really have dropped privs.  if CHROOT
  260.      * was defined, we should also be locked in the jail.  we never need 
  261.      * root privs again and only the config files need to be accessed.
  262.      */
  263.     log ("init_server: running as user %d, group %d", getuid (), getgid ());
  264. #endif /* !WIN32 */
  265.  
  266. #ifndef WIN32
  267.     /* if running in daemon mode, reopen stdout as a log file */
  268.     if (Server_Flags & ON_BACKGROUND)
  269.     {
  270.         char    path[_POSIX_PATH_MAX];
  271.         int     fd;
  272.  
  273.         snprintf (path, sizeof (path), "%s/log", Config_Dir);
  274.         fd = open (path, O_CREAT | O_WRONLY | O_APPEND, S_IRUSR | S_IWUSR);
  275.         if (fd > 0)
  276.         {
  277.             /* close stdout */
  278.             if (dup2 (fd, 1) == -1)
  279.             {
  280.                 logerr ("init_server", "dup2");
  281.                 return -1;
  282.             }
  283.             close (fd);
  284.         }
  285.         else
  286.         {
  287.             logerr ("init_server", path);
  288.             return -1;
  289.         }
  290.     }
  291. #endif
  292.  
  293.     dump_pid ();
  294.  
  295.     /* if not defined in the config file, get the system name */
  296.     if (!Server_Name)
  297.         lookup_hostname ();
  298.     log ("init_server: my hostname is %s", Server_Name);
  299.  
  300.     /* read the user database.  we do this even for routing servers so that
  301.      * we keep track of who is allowed to log in.  eventually this should
  302.      * probably just keep track of the few users that are allowed instead of
  303.      * keeping everyone...
  304.      */
  305.     if (userdb_init ())
  306.     {
  307.         log ("init_server: userdb_init failed");
  308.         return -1;
  309.     }
  310.  
  311.     /* initialize hash tables.  the size of the hash table roughly cuts
  312.        the max number of matches required to find any given entry by the same
  313.        factor.  so a 256 entry hash table with 1024 entries will take rougly
  314.        4 comparisons max to find any one entry.  we use prime numbers here
  315.        because that gives the table a little better spread */
  316.     Users = hash_init (521, (hash_destroy) free_user);
  317.     Channels = hash_init (257, (hash_destroy) free_channel);
  318.     Hotlist = hash_init (521, 0);
  319.     Who_Was = hash_init (1027, (hash_destroy) free_whowas);
  320.  
  321.     Clones = hash_init (1027, (hash_destroy) ip_info_free);
  322.     hash_set_hash_func (Clones, hash_u_int, hash_compare_u_int);
  323.  
  324.     /* routing-only servers don't care about any of this crap... */
  325. #ifndef ROUTING_ONLY
  326.     File_Table = hash_init (2053, 0);
  327. #if RESUME
  328.     MD5 = hash_init (2053, 0);
  329. #endif
  330.     load_bans ();
  331.     load_block ();
  332.     load_filter ();
  333.     load_channels ();
  334.     acl_init ();
  335. #endif /* !ROUTING_ONLY */
  336.     Client_Versions = hash_init (257, (hash_destroy) hashlist_free);
  337.  
  338.     init_random ();
  339.     motd_init ();
  340.     load_server_auth ();
  341.  
  342.     /* figure out what my local ip address is so that when users connect via
  343.      * localhost they can still xfer files.  do this here because
  344.      * server_name can get changed to server_alias below.
  345.      */
  346.     Interface = inet_addr (Listen_Addr);
  347.     if (Interface != INADDR_ANY)
  348.         Server_Ip = Interface;
  349.     else
  350.         Server_Ip = lookup_ip (Server_Name);
  351.  
  352. #ifndef ROUTING_ONLY
  353.     /* set default values for napigator reporting if they were not
  354.      * explicitly set in the config file
  355.      */
  356.     if (global.report_name == NULL)
  357.         global.report_name = STRDUP (Server_Name);
  358.     if (global.report_ip == NULL)
  359.         global.report_ip = STRDUP (my_ntoa (Server_Ip));
  360.     if (global.report_port == 0)
  361.         global.report_port = atoi (Server_Ports->data);
  362.  
  363.     if (global.stat_server)
  364.         log ("init: napigator reporting set to %s -> %s:%d",
  365.                 global.report_name, global.report_ip, global.report_port);
  366. #endif
  367.  
  368.     if (Server_Alias)
  369.     {
  370.         /* switch to using the alias if its defined.   we delay until here
  371.          * because we need to find the local servers' ip when clients connect
  372.          * via localhost.
  373.          */
  374.         if (Server_Name)
  375.             FREE (Server_Name);
  376.         Server_Name = STRDUP (Server_Alias);
  377.         log ("init_server: using %s as my name", Server_Name);
  378.     }
  379.  
  380.     return 0;
  381. }
  382.